<?php

namespace mongrove;

use \Exception;
use \MongoRegex;

/**
 *
 * A field containing a string value.
 *
 * @author Gido Hakvoort <gido@hakvoort.it>
 * @author Michiel Hakvoort <michiel@hakvoort.it>
 *
 */
class StringField extends SimpleField {

    protected $maxLength = null;
    protected $minLength = null;
    protected $pattern = null;

    /**
     * Define a new StringField with the given default value.
     *
     * @param string $default The default value of this field
     */
    public function __construct($default = null) {
        parent :: __construct();

        if($default !== null) {
            $this->setValue($default);
        }
    }

    /**
     * (non-PHPdoc)
     * @see src/mongrove.SimpleField::setValueImpl()
     */
    protected function setValueImpl($value) {
        if($this->value === $value) {
            return false;
        }

        if(!is_string($value)) {
            throw new \Exception("Expected type 'string', got type '".gettype($value)."'");
        }

        if($this->minLength !== null && (strlen($value) < $this->minLength)) {
            throw new \Exception("{$value} is too short, should be >= {$this->minLength}.");
        }

        if($this->maxLength !== null && (strlen($value) > $this->maxLength)) {
            throw new \Exception("{$value} is too long, should be <= {$this->maxLength}.");
        }

        if($this->pattern !== null && filter_var($value, FILTER_VALIDATE_REGEXP, array('options' => array('regexp' => $this->pattern))) === false) {
            throw new \Exception("{$value} does not match pattern.");
        }

        $this->value = $value;

        return true;
    }

    /**
     * Set a regular expression to which this field needs to adhere.
     *
     * @param string $pattern The pattern to which this field needs to adhere
     * @return StringField
     */
    public function setPattern($pattern) {
        $this->pattern = $pattern;

        return $this;
    }

    /**
     * Set the maximum (inclusive) required length for strings in this field.
     *
     * @param int $maxLength The maximum allowed length for this field
     * @throws \Exception Thrown when $maxLength is not an integer
     * @return StringField
     */
    public function setMaxLength($maxLength) {
        if(!is_int($maxLength)) {
            throw new \Exception("\$maxLength should be an integer value.");
        }

        $this->maxLength = ($maxLength === null) ? $maxLength : (int)$maxLength;

        return $this;
    }

    /**
     * Set the minimum (inclusive) required length of strings allowed in this field.
     *
     * @param int $minLength The minimum allowed length for this field
     * @throws \Exception Throw when $minLength is not an integer
     * @return StringField
     */
    public function setMinLength($minLength) {
        if(!is_int($minLength)) {
            throw new \Exception("\$minLength should be an integer value.");
        }

        $this->minLength = ($minLength === null) ? $minLength : (int)$minLength;

        return $this;
    }

    /**
     * (non-PHPdoc)
     * @see src/mongrove.SimpleField::rewriteQuery()
     */
    public function rewriteQuery(array $partialQuery) {
        foreach($partialQuery as $operator => $value) {
            if($operator === Command :: CON_OP_LIKE) {
                unset($partialQuery[$operator]);
                $value = trim($value);
                if(!isset($value[0]) || $value[0] !== '/') {
                    $value = "/{$value}/";
                }
                $partialQuery[Command :: CON_OP_LIKE] = new MongoRegex($value);
            }
        }

        return $partialQuery;
    }
}